package it.unica.informatica.enotes.notes;

import android.os.Parcel;
import android.os.Parcelable;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.TimeZone;

/**
 * This class manages a typical note and its contents
 *
 * @author Mirko Marras
 * @version 1.0
 */

public class Note implements Parcelable, Comparable<Note> {

   private static final int MAX_TITLE_SIZE = 200;

   private Long id;
   private String title;
   private String content;
   private Date lastChange;
   private ArrayList<String> tags;
   private ArrayList<AttachmentItem> attachments;

   /**
    * Construct a new note object with default values
    */
   public Note() {
      this.id = Long.valueOf(0);
      this.title = "";
      this.content = "";
      this.lastChange = new Date();
      this.attachments = new ArrayList<AttachmentItem>();
      this.tags = new ArrayList<String>();
   }

   /**
    * Construct a new note object with the values passed as parameters
    *
    * @param id         The id of the new note
    * @param title      The title of the new note
    * @param lastChange The date of the last change of the new note
    */
   public Note(Long id, String title, Date lastChange) {
      this.id = id;

      this.title = title;
      if(title.length() > MAX_TITLE_SIZE) {
         this.title = title.substring(0, MAX_TITLE_SIZE);
      }

      this.lastChange = lastChange;
      this.content = "";
      this.attachments = new ArrayList<AttachmentItem>();
      this.tags = new ArrayList<String>();
   }

   /**
    * Construct a new note object with the values passed as parameters
    *
    * @param id         The id of the new note
    * @param title      The title of the new note
    * @param lastChange The date of the last change of the new note
    */
   public Note(Long id, String title, String lastChange) {
      this.id = id;

      this.title = title;
      if(title.length() > MAX_TITLE_SIZE) {
         this.title = title.substring(0, MAX_TITLE_SIZE);
      }

      this.setLastChangeFormatter(lastChange);
      this.content = "";
      this.attachments = new ArrayList<AttachmentItem>();
      this.tags = new ArrayList<String>();
   }

   /**
    * Get the id of this note object
    *
    * @return The id of the note object
    */
   public Long getId() {
      return this.id;
   }

   /**
    * Set the id of this note object
    *
    * @param id The new id for the note object
    */
   public void setId(Long id) {
      this.id = id;
   }

   /**
    * Get the title of this note object
    *
    * @return The title of the note object
    */
   public String getTitle() {
      return this.title;
   }

   /**
    * Set the title of this note object
    *
    * @param title The new title for the note object
    */
   public void setTitle(String title) {
      this.title = title;
      if(title.length() > MAX_TITLE_SIZE) {
         this.title = title.substring(0, MAX_TITLE_SIZE);
      }
   }

   /**
    * Get the text content of this note object
    *
    * @return The text content of the note object
    */
   public String getContent() {
      return this.content;
   }

   /**
    * Set the text content of this note object
    *
    * @param content The new text content for the note object
    */
   public void setContent(String content) {
      this.content = content;
   }

   /**
    * Get the date of the last change of this note object
    *
    * @return The date of the last change of the note object
    */
   public Date getLastChange() {
      return this.lastChange;
   }

   /**
    * Set the date of the last change of this note object
    *
    * @param lastChange The new date of the last change of the note object
    */
   public void setLastChange(Date lastChange) {
      this.lastChange = lastChange;
   }

   /**
    * Get the date of the last change of this note object
    *
    * @return The date of the last change of the note object as a formatted string
    */
   public String getLastChangeFormatter() {
      DateFormat dfm = new SimpleDateFormat("HH:mm:ss dd/MM/yyyy");
      dfm.setTimeZone(TimeZone.getTimeZone("Europe/Zurich"));
      return dfm.format(this.lastChange);
   }

   /**
    * Set the date of the last change of this note object
    *
    * @param date The date of the last change of the note object as a formatted string
    */
   public void setLastChangeFormatter(String date) {
      DateFormat dfm = new SimpleDateFormat("HH:mm:ss dd/MM/yyyy");
      dfm.setTimeZone(TimeZone.getTimeZone("Europe/Zurich"));
      try {
         this.lastChange = dfm.parse(date);
      } catch (ParseException e) {
         e.printStackTrace();
      }
   }

   /**
    * Get the list of all the tags associated to this note object
    *
    * @return The list of all the tags for the note object
    */
   public ArrayList<String> getTags() {
      return this.tags;
   }

   /**
    * Set the list of all the tags associated to this note object
    *
    * @param tags The new list of tags associated to the note object
    */
   public void setTag(ArrayList<String> tags) {
      this.tags = (ArrayList<String>) tags.clone();
   }

   /**
    * Get the list of all the attachments associated to this note object
    *
    * @return The list of all the attachments for the note object
    */
   public ArrayList<AttachmentItem> getAttachments() {
      return this.attachments;
   }

   /**
    * Set the list of all the attachments associated to this note object
    *
    * @param attachments The new list of attachments associated to the note object
    */
   public void setAttachments(ArrayList<AttachmentItem> attachments) {
      this.attachments = (ArrayList<AttachmentItem>) attachments.clone();
   }

   /**
    * Check if the note object is empty
    *
    * @return True if the note object is empty, false otherwise
    */
   public boolean isEmpty() {
      return this.title.equals("");
   }

   /**
    * Compare this note object with another based on the date of the last change
    *
    * @param another The second note object to compare with this
    * @return A negative value if the date of the last change of this note object precedes another last change,
    * a position value if it is after the another last change or 0 if they are the same
    */
   @Override
   public int compareTo(Note another) {
      return another.getLastChange().compareTo(this.lastChange);
   }

   @Override
   public boolean equals(Object o) {
      if (this == o) return true;
      if (!(o instanceof Note)) return false;

      Note note = (Note) o;

      if (!attachments.equals(note.attachments)) return false;
      if (!content.equals(note.content)) return false;
      if (!tags.equals(note.tags)) return false;
      if (!title.equals(note.title)) return false;

      return true;
   }

   @Override
   public int hashCode() {
      int result = title.hashCode();
      result = 31 * result + content.hashCode();
      result = 31 * result + tags.hashCode();
      result = 31 * result + attachments.hashCode();
      return result;
   }

    /* ********************************************************************************************
     *                                        PARCELABLE METHODS                                  *
     **********************************************************************************************/

   public static final Parcelable.Creator<Note> CREATOR
           = new Parcelable.Creator<Note>() {
      public Note createFromParcel(Parcel in) {
         return new Note(in);
      }

      public Note[] newArray(int size) {
         return new Note[size];
      }
   };

   /**
    * Describe the content of the parcelable
    *
    * @return Always zero
    */
   public int describeContents() {
      return 0;
   }

   /**
    * Save a note in the parcelable
    *
    * @param out   The output parcelable
    * @param flags Flags used to save
    */
   public void writeToParcel(Parcel out, int flags) {
      out.writeLong(id);
      out.writeString(title);
      out.writeString(content);
      out.writeString(this.getLastChangeFormatter());
      out.writeStringList(tags);
      out.writeTypedList(attachments);
   }

   /**
    * Recreate a note from the parcelable
    *
    * @param in The parcelable where read
    */
   private Note(Parcel in) {
      this.id = in.readLong();
      this.title = in.readString();
      this.content = in.readString();
      this.setLastChangeFormatter(in.readString());
      in.readStringList(tags);
      in.readTypedList(attachments, AttachmentItem.CREATOR);
   }
}
